package com.glela.statistics.service.impl;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.glela.common.constant.BaseConstants;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.glela.cache.redis.RedisKeys;
import com.glela.cache.redis.RedisUtil;
import com.glela.common.util.DateUtil;
import com.glela.common.util.DateUtils;
import com.glela.common.util.NumberUtil;
import com.glela.statistics.mapper.OrderStatisticsMapper;
import com.glela.statistics.model.UserEarnings;
import com.glela.statistics.service.UserEarningsService;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.Transaction;

/**
 * 用户收益
 * @author gwq<br>
 *	订单的统计都支付时间为准。
 *	如订单在退款中，对应的收益和销售额度不会扣减，如退款成功，对应的收益和销售额扣减。
 *	App内收益统计当前店铺成交订单产生的收益，只统计直接收益，不包含间接收益和妆币。

 */
@Service("UserEarningsService")
public class UserEarningsServiceImpl implements UserEarningsService {
	
	private static Logger logger = LoggerFactory.getLogger(UserEarningsServiceImpl.class);
	private static int [] CommisionStatusArray={1,2,3,4,10,17};// 1 2 3分佣 ，4 手工 ，10嗨购，17 其他分佣
	private static int [] OrderStatusArray={1,2,3,4,10,17};// 1 2 3分佣 ，4 手工 ，10嗨购，17 其他分佣
	private static String EarningName [] ={"accumulatedEarnings","uncollectedEarnings","todayEarnings","monthEarnings","monthSalesVolume"};
	private static int EARNINGDBINDEX=6;//收益默认redis库
	private static int MAXWHILETIMES=100;//redis事务失败最大循环次数
	private static long SLEEPTIME=1000;//redis事务失败后延迟执行
	@Autowired
	private OrderStatisticsMapper orderStatisticsMapper;
	@Autowired
	private RedisUtil redisUtil;

	@Override
	public Long AccumulatedEarnings(Long useID) {
		List<Long> reslut=orderStatisticsMapper.selectAccumulatedEarningsCommision(useID,CommisionStatusArray);
		return  sum(reslut);
	}
	@Override
	public Long TodayEarnings(Long useID) {
		List<Long> reslut=orderStatisticsMapper.selectTodayEarningsCommision(useID,CommisionStatusArray,DateUtil.getDays(-1),DateUtil.getNow());
		return  sum(reslut);
	}

	@Override
	public Long UncollectedEarnings(Long useID) {
		List<Long> reslut=orderStatisticsMapper.selectUncollectedEarningsCommision(useID,CommisionStatusArray);
		return  sum(reslut);
	}
	@Override
	public Long MonthEarnings(Long useID) {
		List<Long> reslut=orderStatisticsMapper.selectTodayEarningsCommision(useID,OrderStatusArray,DateUtil.getfirstDayOfMonth(),DateUtil.getNow());
		return  sum(reslut);
	}

	@Override
	public Long MonthSalesVolume(Long useID) {
		List<Map<String, Object>> list = orderStatisticsMapper.selectMonthSalesVolume(useID, DateUtil.getfirstDayOfMonth(),DateUtil.getNow());
		List<Long> reslut = new ArrayList<Long>();
		for (Map<String, Object> tempMap : list) {
			for (String str : tempMap.keySet()) {
				reslut.add(Long.parseLong(tempMap.get(str).toString()));
			}
		}
		return sum(reslut);
	}
	@Override
	public UserEarnings selectEarningsWithCache(Long userID) {
		UserEarnings userEarnings=new UserEarnings();
		try {
			Map<String,String> MapEarnings=EarningsCache(userID);
			//最小值为0.00
			for(String keyName:MapEarnings.keySet()){
                long value=Long.parseLong(MapEarnings.get(keyName));
                MapEarnings.put(keyName,(String.valueOf(value>0?value:0)));
            }
			userEarnings.setAccumulatedEarnings(NumberUtil.changeF2YWithScale(Long.parseLong(MapEarnings.get("accumulatedEarnings"))));
			userEarnings.setTodayEarnings(NumberUtil.changeF2YWithScale(Long.parseLong(MapEarnings.get("todayEarnings"))));
			userEarnings.setUncollectedEarnings(NumberUtil.changeF2YWithScale(Long.parseLong(MapEarnings.get("uncollectedEarnings"))));
			userEarnings.setMonthEarnings(NumberUtil.changeF2YWithScale(Long.parseLong(MapEarnings.get("monthEarnings"))));
			userEarnings.setMonthSalesVolume(NumberUtil.changeF2YWithScale(Long.parseLong(MapEarnings.get("monthSalesVolume"))));
			userEarnings.setUserId(userID);
		} catch (Exception e) {
			userEarnings.setAccumulatedEarnings("0.00");
			userEarnings.setTodayEarnings("0.00");
			userEarnings.setUncollectedEarnings("0.00");
			userEarnings.setMonthEarnings("0.00");
			userEarnings.setMonthSalesVolume("0.00");
			userEarnings.setUserId(userID);
			logger.error("获取收益明细失败：{}",e.getMessage());
		}
		return   userEarnings;
	}

	@Override
	public void CalculateEarningsOrderWithCache(Map<Long, Integer> userCommisionMap, Long openStoreUserId, int totalFee, String payTime) {
		boolean calculateDay = ((DateUtils.compare_date_HHmmss(payTime, DateUtil.getDays(-1)) >= 0) &&
				(DateUtils.compare_date_HHmmss(payTime, DateUtil.getNow()) <= 0)) ? true : false;
		boolean calculateMonth = ((DateUtils.compare_date_HHmmss(payTime, DateUtil.getfirstDayOfMonth()) >= 0) &&
				(DateUtils.compare_date_HHmmss(payTime, DateUtil.getNow()) <= 0)) ? true : false;
		for (Long userId : userCommisionMap.keySet()) {
			String keyName = new StringBuffer().append(RedisKeys.USER_EARNINGS).append(DateUtil.currentYourDate(BaseConstants.DATE_FORMAT_YYYYMMDD)).append(":").append(userId).toString();
			boolean init = true;
			if (redisUtil.exists(keyName,EARNINGDBINDEX)) {// 存在
				init = false;
			} else {
				EarningsCache(userId);//如果key 不存在 就初始化
				continue;
			}
			// 更新redis记录 开启事务
			int i = 0;
			while ((i++) < MAXWHILETIMES) {
				Jedis jedis = null;
				try {
					jedis = redisUtil.getJedis(EARNINGDBINDEX);
					jedis.watch(keyName);
					Transaction tran = jedis.multi();
					for (String name : EarningName) {
						if (StringUtils.equalsAny(name, "accumulatedEarnings", "uncollectedEarnings")) {//累计收益 待收收益
							tran.hincrBy(keyName, name, userCommisionMap.get(userId));
							continue;
						}
						if (StringUtils.equals("todayEarnings", name) && calculateDay) {//今日收益 支付之间在今天内
							tran.hincrBy(keyName, name, userCommisionMap.get(userId));
							continue;
						}
						if (StringUtils.equals("monthEarnings", name) && calculateMonth) {//本月收益 支付之间在本月内
							tran.hincrBy(keyName, name, userCommisionMap.get(userId));
							continue;
						}
						if (StringUtils.equals("monthSalesVolume", name) && calculateMonth && (!init)) {//月销售额
							tran.hincrBy(keyName, name, userCommisionMap.get(userId));
							continue;
						}
					}
					List<Object> results = tran.exec();
					if (results == null || results.size() == 0) {//收益计算失败 延迟计算
						jedis.unwatch();
						jedis.close();
						Thread.sleep(SLEEPTIME);
						continue;
					}
					jedis.unwatch();
					jedis.close();
					break;
				} catch (Exception e) {
					if (jedis != null) {
						jedis.unwatch();
						jedis.close();
					}
					logger.error("收益计算失败:{}", e.getMessage());
				}
			}
		}
	}

	protected long sum(List<Long> result) {
		long sum = 0L;
		for (Long temp : result) {
			sum += (temp == null ? 0L : temp);
		}
		return sum;
	}

	@Override
	public void CalculateEarningsAfterSaleWithCache(Map<Long, Integer> userCommisionMap, Long openStoreUserId, int totalFee, String payTime) {
	    boolean calculateDay = ((DateUtils.compare_date_HHmmss(payTime, DateUtil.getDays(-1)) >= 0) &&
				(DateUtils.compare_date_HHmmss(payTime, DateUtil.getNow()) <= 0)) ? true : false;
		boolean calculateMonth = ((DateUtils.compare_date_HHmmss(payTime, DateUtil.getfirstDayOfMonth()) >= 0) &&
				(DateUtils.compare_date_HHmmss(payTime, DateUtil.getNow()) <= 0)) ? true : false;
		for (Long userId : userCommisionMap.keySet()) {
			String keyName = new StringBuffer().append(RedisKeys.USER_EARNINGS).append(DateUtil.currentYourDate(BaseConstants.DATE_FORMAT_YYYYMMDD)).append(":").append(userId).toString();
			boolean init = true;
			if (redisUtil.exists(keyName,EARNINGDBINDEX)) {// 存在
				init = false;
			} else {
				EarningsCache(userId);//如果key 不存在 就初始化
				continue;
			}
			// 更新redis记录 开启事务
			int i = 0;
			while ((i++) < MAXWHILETIMES) {
				Jedis jedis = null;
				try {
					jedis = redisUtil.getJedis(EARNINGDBINDEX);
					jedis.watch(keyName);
					Transaction tran = jedis.multi();
					for (String name : EarningName) {
						if (StringUtils.equalsAny(name, "accumulatedEarnings", "uncollectedEarnings")) {//累计收益 待收收益
							tran.hincrBy(keyName, name, userCommisionMap.get(userId));
							continue;
						}
						if (StringUtils.equals("todayEarnings", name) && calculateDay) {//今日收益 支付之间在今天内
							tran.hincrBy(keyName, name, userCommisionMap.get(userId));
							continue;
						}
						if (StringUtils.equals("monthEarnings", name) && calculateMonth) {//本月收益 支付之间在本月内
							tran.hincrBy(keyName, name, userCommisionMap.get(userId));
							continue;
						}
						if (StringUtils.equals("monthSalesVolume", name) && calculateMonth && (!init)) {//月销售额
							tran.hincrBy(keyName, name, userCommisionMap.get(userId));
							continue;
						}
					}
					List<Object> results = tran.exec();
					if (results == null || results.size() == 0) {//收益计算失败 延迟计算
						jedis.unwatch();
						jedis.close();
						Thread.sleep(SLEEPTIME);
						continue;
					}
					jedis.unwatch();
					jedis.close();
					break;
				} catch (Exception e) {
					if (jedis != null) {
						jedis.unwatch();
						jedis.close();
					}
					logger.error("收益计算失败:{}", e.getMessage());
				}
			}
		}
	}

	/**
	 * 获取收益缓存 如果又不存在的就初始化
	 */
	protected Map<String, String> EarningsCache(Long userId) {
		String keyName = new StringBuffer().append(RedisKeys.USER_EARNINGS).append(DateUtil.currentYourDate(BaseConstants.DATE_FORMAT_YYYYMMDD)).append(":").append(userId).toString();
		Map<String, String> MapEarnings = new HashMap<String, String>();
		if (redisUtil.exists(keyName,EARNINGDBINDEX)) {// 存在
			MapEarnings = redisUtil.hgetAll(keyName, EARNINGDBINDEX);
		} else {// 初始化
			Jedis jedis = redisUtil.getJedis(EARNINGDBINDEX);
			jedis.watch(keyName);
			Transaction tran = jedis.multi();
			MapEarnings.putAll(CalculateAccumulatedEarnings(userId));
			MapEarnings.putAll(CalculateUncollectedEarnings(userId));
			MapEarnings.putAll(CalculateTodayEarnings(userId));
			MapEarnings.putAll(CalculateMonthEarnings(userId));
			MapEarnings.putAll(CalculatMonthSalesVolume(userId));
			tran.hmset(keyName, MapEarnings);
			List<Object> results = tran.exec();
			if (results == null || results.size() == 0) {// 初始化失败 被其他线程优先初始化了
				MapEarnings = redisUtil.hgetAll(keyName, EARNINGDBINDEX);
			}
			jedis.unwatch();
			jedis.close();
		}
		return MapEarnings;
	}
	/**初始化 累计收益*/
	protected Map<String,String> CalculateAccumulatedEarnings(Long userId) {
		Long accumulatedEarnings=this.AccumulatedEarnings(userId);
		Map<String,String> map=new HashMap<String,String>();
		map.put("accumulatedEarnings",String.valueOf(accumulatedEarnings));
		return map;
	}
	/**初始化 未到账收益*/
	protected Map<String,String> CalculateUncollectedEarnings(Long userId) {
		Long uncollectedEarnings=this.UncollectedEarnings(userId);
		Map<String,String> map=new HashMap<String,String>();
		map.put("uncollectedEarnings",String.valueOf(uncollectedEarnings));
		return map;
	}
	/**初始化 今日收益*/
	protected Map<String,String> CalculateTodayEarnings(Long userId) {
		Long todayEarnings=this.TodayEarnings(userId);
		Map<String,String> map=new HashMap<String,String>();
		map.put("todayEarnings",String.valueOf(todayEarnings));
		return map;
	}
	/**初始化 本月收益*/
	protected Map<String,String> CalculateMonthEarnings(Long userId) {
		Long monthEarnings=this.MonthEarnings(userId);
		Map<String,String> map=new HashMap<String,String>();
		map.put("monthEarnings",String.valueOf(monthEarnings));
		return map;
	}
	/**初始化 本月销售额*/
	protected Map<String,String> CalculatMonthSalesVolume(Long userId) {
		Long monthSalesVolume=this.MonthSalesVolume(userId);
		Map<String,String> map=new HashMap<String,String>();
		map.put("monthSalesVolume",String.valueOf(monthSalesVolume));
		return map;
	}
}
